package xyz.thoughtset.viewer.executor.blocks.executor;

import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import xyz.thoughtset.viewer.common.exc.exceptions.ExecException;
import xyz.thoughtset.viewer.modules.step.entity.LoopBody;
import xyz.thoughtset.viewer.executor.blocks.constants.NodeConstant;
import xyz.thoughtset.viewer.modules.step.entity.block.BlockBodyEle;
import xyz.thoughtset.viewer.modules.step.entity.block.BlockInfo;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.LongAdder;

@Component
public class LoopBlockExecutor extends AbstractBlockExecutor<LoopBody>  {


    @Override
    protected Object doQuery(BlockInfo block, LoopBody body, Map<String, Object> params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException {
        List<Object> results = new ArrayList<>();
        context.setVariable(NodeConstant.DATA_NODE, results);
        params.put(NodeConstant.DATA_NODE, results);
        LongAdder index = new LongAdder();
        context.setVariable(NodeConstant.CURRENT_DATA_NODE_INDEX, index);
        params.put(NodeConstant.CURRENT_DATA_NODE_INDEX, index);
        if (body.isDoFirst()) {
            do {
                doLoop(results,body, params, parser, context,index);
            }while (checkCondition(body, params, parser, context));
        }else {
            while (checkCondition(body, params, parser, context)) {
                doLoop(results,body, params, parser, context,index);
            }
        }
        params.remove(NodeConstant.DATA_NODE);
        context.setVariable(NodeConstant.DATA_NODE,null);
        context.setVariable(NodeConstant.CURRENT_DATA_NODE_INDEX, null);
        params.remove(NodeConstant.CURRENT_DATA_NODE_INDEX);
        return results;
    }

    protected void doLoop(List<Object> results,LoopBody body, Map<String, Object> params, ExpressionParser parser, StandardEvaluationContext context,LongAdder index) {
        List eleResults = new ArrayList<>(body.getBodyEles().size()+1);
        for (BlockBodyEle ele : body.getBodyEles()) {
            eleResults.add(execNode(ele, params, parser, context));
        }
        results.add(eleResults);
        index.increment();
    }

    protected boolean checkCondition(LoopBody body, Map<String, Object> params, ExpressionParser parser, StandardEvaluationContext context) {
        String condition = body.getLoopRepx();
        if (condition != null && !condition.isEmpty()) {
            Object result = parser.parseExpression(condition.startsWith("#")?condition:"#"+condition).getValue(context);
            if (result instanceof Boolean) {
                return result != null && ((Boolean) result).booleanValue();
            }
            return !ObjectUtils.isEmpty(result);
        }
        return false;
    }


}
